package com.cicc.beergamevirtualsimulationsystem.entity;

import com.alibaba.fastjson.JSON;
import com.cicc.beergamevirtualsimulationsystem.common.enums.userTypeEnum.RoleType;
import com.cicc.beergamevirtualsimulationsystem.common.webSocket.config.WebSocketMessageSender;
import com.cicc.beergamevirtualsimulationsystem.common.webSocket.holder.WebSocketSessionHolder;
import com.cicc.beergamevirtualsimulationsystem.common.webSocket.message.Impl.*;
import com.cicc.beergamevirtualsimulationsystem.model.parameter.req.InnerGameParameterUpdateReq;
import com.cicc.beergamevirtualsimulationsystem.model.roleBinding.RoleBindingReq;
import com.cicc.beergamevirtualsimulationsystem.model.webSocket.RoomRolesVO;
import com.cicc.beergamevirtualsimulationsystem.service.ParameterService;
import com.cicc.beergamevirtualsimulationsystem.service.RecordService;
import com.cicc.beergamevirtualsimulationsystem.service.RoomService;
import lombok.Data;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Component
@Data

public final class RoomInfoManager {

    private static final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
    //玩家角色选择情况
    private static final Map<String, Map<String, String>> roomRoles = new ConcurrentHashMap<>();
    //最大回合数
    private static final Map<String, AtomicInteger> remainingCountdowns = new ConcurrentHashMap<>();
    //当前回合数
    private static final Map<String, AtomicInteger> CurrentRound = new ConcurrentHashMap<>();
    //每回合游戏时长
    private static final Map<String, Integer> durations = new ConcurrentHashMap<>();
    //判断是否暂停
    private static final Map<String, AtomicBoolean> countdownRunning = new ConcurrentHashMap<>();
    //每个房间倒计时对应的线程
    private static final Map<String, Future<?>> countdownFutures = new ConcurrentHashMap<>();
    //每个房间角色限制
    private static final Map<String, Map<String, Integer>> roleLimits = new ConcurrentHashMap<>();
    //角色id映射
    private static final Map<String, Map<String, String>> roleIdMapping = new HashMap<>();
    // 角色id和角色类型映射
    private static final Map<Integer, String> roleNames = new HashMap<>();
    //房间内所有玩家的昵称
    private static final Map<String, Map<String, String>> roomNicknames = new ConcurrentHashMap<>();
    //主持人每回合的订单量
    private static final Map<String, Integer> customerOrder = new ConcurrentHashMap<>();

    //回合内修改配置
    private static final Map<String, InnerGameParameterUpdateReq> InnerGameParameter = new ConcurrentHashMap<>();


    private static RoomService roomService;


    private static RecordService recordService;
    private static ParameterService parameterService;

    static {
        roleNames.put(RoleType.CUSTOMER.getCode(), RoleType.CUSTOMER.getDesc());
        roleNames.put(RoleType.FACTORY.getCode(), RoleType.FACTORY.getDesc());
        roleNames.put(RoleType.RETAILER.getCode(), RoleType.RETAILER.getDesc());
        roleNames.put(RoleType.SUPPLIER.getCode(), RoleType.SUPPLIER.getDesc());
    }


    private RoomInfoManager(RoomService roomService, RecordService recordService, ParameterService parameterService) {

        RoomInfoManager.roomService = roomService;
        RoomInfoManager.recordService = recordService;
        RoomInfoManager.parameterService = parameterService;

    }


    //初始化房间信息
    public static void initializeRoom(String roomId, int durationSeconds, int initialCountdowns, Map<String, Integer> Limits, Map<String, String> mapping, String masterId) {

//        System.out.println("masterId=="+masterId);
        durations.put(roomId, durationSeconds);
        remainingCountdowns.put(roomId, new AtomicInteger(initialCountdowns));
        CurrentRound.put(roomId, new AtomicInteger(1));
        roomRoles.computeIfAbsent(roomId, k -> new ConcurrentHashMap<>())
                .put(masterId, RoleType.CUSTOMER.getCode().toString());
        roomNicknames.computeIfAbsent(roomId, k -> new ConcurrentHashMap<>());
        roleLimits.put(roomId, Limits);
        roleIdMapping.put(roomId, mapping);
        customerOrder.put(roomId, 0);
        InnerGameParameter.put(roomId, new InnerGameParameterUpdateReq());

//        Map<String, String> stringStringMap = roomRoles.get(roomId);

//        System.out.println("============"+stringStringMap.toString());
//        printData(roomId);
    }

    //打印所有房间数据
    public static void printData(String roomId) {
        System.out.println("Room ID: " + roomId);
        System.out.println("剩余时间: " + durations.get(roomId));
        System.out.println("剩余回合: " + remainingCountdowns.get(roomId));
        System.out.println("当前角色分配情况: " + roomRoles.get(roomId));
        System.out.println("角色限制情况: " + roleLimits.get(roomId));
    }

    //回合内修改房间配置
    public static void updateRoomConfig(WebSocketSession session, String roomId, InnerGameParameterUpdateReq dto) {
        if (Objects.isNull(dto.getCycles()) || Objects.isNull(dto.getGameTime())) {
            WebSocketMessageSender.send(session, new InnerGameParameterUpdateJsonWebSocketMessage("请输入正确的配置参数"));
            return;
        }
        // 当前回合 大于 要修改的回合数
        if (CurrentRound.get(roomId).get() > dto.getCycles()) {
            WebSocketMessageSender.send(session, new InnerGameParameterUpdateJsonWebSocketMessage("修改的回合数需大于当前修改的回合数"));
            return;
        }
        InnerGameParameter.put(roomId, dto);
        //修改数据库
        parameterService.updateInnerGameParameter(InnerGameParameter.get(roomId));
        WebSocketMessageSender.sendMessageToRoom(roomId, new InnerGameParameterUpdateJsonWebSocketMessage("房主已修改当前房间配置"));
    }


    public static void startCountdown(String roomId) {
        // 检查是否已经有倒计时在运行，如果没有则启动新的倒计时
        if (countdownRunning.putIfAbsent(roomId, new AtomicBoolean(true)) == null) {
            AtomicInteger durationSeconds = new AtomicInteger(durations.get(roomId));
            AtomicInteger remainingCountdownsRef = remainingCountdowns.get(roomId);
            AtomicInteger currentRound = CurrentRound.get(roomId);

            if (durationSeconds.get() > 0 && currentRound.get() <= remainingCountdownsRef.get()) {
                Future<?> future = null; // 初始化future为null
                Future<?> finalFuture = future;

                future = executorService.scheduleAtFixedRate(() -> {
                    try {
//                        if (Boolean.valueOf(String.valueOf(countdownRunning.get(roomId)))) {
                        // 发送当前剩余时间的消息
                        int currentDuration = durationSeconds.get();
                        WebSocketMessageSender.sendMessageToRoom(roomId, new CurrentTimeWbeSocketMessage(
                                "round:" + currentRound.get() + "," +
                                        "second:" + currentDuration + "," +
                                        "maxRound:" + remainingCountdowns.get(roomId) + "," +
                                        "maxDurations:" + durations.get(roomId)));

                        // 减少剩余倒计时次数
                        if (currentDuration > 0) {
                            durationSeconds.decrementAndGet();
                        } else {
                            if (InnerGameParameter.get(roomId).isChange()) {
                                //修改数据库
//                                parameterService.updateInnerGameParameter(InnerGameParameter.get(roomId));
                                // todo:修改数据库
                                System.out.println("=======房间配置修改了====>周期：" + InnerGameParameter.get(roomId).getCycles() + ",时间：" + InnerGameParameter.get(roomId).getGameTime());
                                durationSeconds.set(InnerGameParameter.get(roomId).getGameTime());
                                remainingCountdownsRef.set(InnerGameParameter.get(roomId).getCycles());
                                durations.put(roomId, InnerGameParameter.get(roomId).getGameTime());
                                System.out.println("=======房间配置修改后的值====>周期：" + remainingCountdownsRef.get() + ",时间：" + durationSeconds.get());
                                InnerGameParameter.get(roomId).setChange(false);
                            }
                            //先结算这一轮的数据
                            recordService.settle(roomId, currentRound.get());
                            // 如果当前轮次结束，增加轮次并重置倒计时
                            currentRound.incrementAndGet();
                            //初始化下一轮数据
                            recordService.initRecord(roomId, currentRound.get(), customerOrder.get(roomId));
                            //结算完成后将主持人订单重置为0
                            customerOrder.put(roomId, 0);
                            WebSocketMessageSender.sendMessageToRoom(roomId, new RoundEndJsonWebSocketMessage("回合结束"));
                            durationSeconds.set(durations.get(roomId)); // 重置倒计时
                        }
//                        }
                    } catch (Exception e) {
                        System.err.println("发送消息失败: " + e.getMessage());
                    } finally {
                        // 如果倒计时结束，移除倒计时任务
                        if (currentRound.get() > remainingCountdownsRef.get()) {
                            roomService.closeRoom(roomId);
                            WebSocketMessageSender.sendMessageToRoom(roomId, new GameEndJsonWebSocketMessage("游戏结束"));
                            clearRoom(roomId, 0);
                            finalFuture.cancel(true); // 取消定时任务
                        }
                    }
                }, 0, 1, TimeUnit.SECONDS);

                if (future != null) {
                    countdownFutures.put(roomId, future);
                }
            }
        }
    }

    //TODO: 暂停倒计时
    public static void stopCountdown(String roomId) {
        countdownRunning.get(roomId).set(false);
    }

    //TODO: 继续倒计时
    public static void continueCountdown(String roomId) {
        countdownRunning.get(roomId).set(true);
    }

    //清除房间相关所有数据
    public static void clearRoom(String roomId, Integer type) {

        //判断是否有数据有的话就删除
        if (countdownRunning.get(roomId) != null) {
            countdownRunning.remove(roomId);
        }
        if (CurrentRound.get(roomId) != null) {
            CurrentRound.remove(roomId);
        }
        if (remainingCountdowns.get(roomId) != null) {
            remainingCountdowns.remove(roomId);
        }
        if (durations.get(roomId) != null) {
            durations.remove(roomId);
        }
        if (roomRoles.get(roomId) != null) {
            roomRoles.remove(roomId);
        }
        if (roomNicknames.get(roomId) != null && type == 0) {
            roomNicknames.remove(roomId);
        }

        if (roleLimits.get(roomId) != null) {
            roleLimits.remove(roomId);
        }
        if (customerOrder.get(roomId) != null) {
            customerOrder.remove(roomId);
        }
        if (InnerGameParameter.get(roomId) != null) {
            InnerGameParameter.remove(roomId);
        }

        if (countdownFutures.get(roomId) != null) {
            countdownFutures.get(roomId).cancel(true);
            countdownFutures.remove(roomId);

        }

    }

    //获取当前房间的基本信息
    public static String getRoomInfo(String roomId, String userId) throws Exception {
        // 选择情况
        Map<String, String> stringStringMap = roomRoles.get(roomId);

        System.out.println("==========" + stringStringMap.toString());

        Map<String, Long> collect = stringStringMap.values().stream()
                .collect(Collectors.groupingBy(role -> role, Collectors.counting()));
        // 房间角色配置
        Map<String, Integer> stringIntegerMap = roleLimits.get(roomId);

        // 获取所有唯一的角色类型
        Set<String> allRoles = new HashSet<>(collect.keySet());
        allRoles.addAll(stringIntegerMap.keySet());
        // 合并两个 Map 的数据
        List<Map<String, Object>> result = new ArrayList<>();
        for (String role : allRoles) {
            int roleType = Integer.parseInt(role);
            Map<String, Object> entry = new HashMap<>();
            entry.put("roleType", roleType);
            entry.put("roleName", roleNames.get(roleType));
            entry.put("peizhi1count", stringIntegerMap.getOrDefault(role, 0));
            entry.put("joincount", collect.getOrDefault(role, 0L).intValue());
            // 判断 用户是否选择了当前角色 isSelect 字段
            boolean isSelect = stringStringMap.entrySet().stream()
                    .anyMatch(entry1 -> entry1.getKey().equals(userId) && entry1.getValue().equals(role));
            entry.put("isSelect", isSelect);
            if (isSelect) {
                entry.put("button", "退出");
            } else {
                entry.put("button", "加入");
            }

            result.add(entry);
        }

        //
        Map<String, String> userNickNames = roomNicknames.get(roomId);

        List<Map<String, Object>> entryMap = new ArrayList<>();
        if (userNickNames != null) {
            userNickNames.forEach((playerId, nickName) -> {
                Map<String, Object> entry = new HashMap<>();
                if (stringStringMap.containsKey(playerId)) {
                    entry.put("isSelect", true);
                    entry.put("nickName", nickName);
                } else {
                    entry.put("isSelect", false);
                    entry.put("nickName", nickName);
                }
                entryMap.add(entry);
            });
        }


        RoomRolesVO testVO = new RoomRolesVO();
        testVO.setRoomRolesData(result);
        testVO.setRoomRolesStatus(entryMap);


        String jsonString = JSON.toJSONString(testVO);

//        System.out.println(userId + "的结果-------------------:" + jsonString);

        // 返回结果
        return jsonString;
    }

    //选择角色
    public static void selectRole(String roomId, String playerId, String role) throws Exception {

        Map<String, String> stringStringMap = roomRoles.get(roomId);


        WebSocketSession session = WebSocketSessionHolder.getSession(roomId, playerId);
        //统计对应角色的数量
        long count = stringStringMap.values().stream().filter((s) -> s.equals(role)).count();

        //判断用户是否已经选择了角色
        if (stringStringMap.containsKey(playerId)) {
            System.out.println("角色选择失败，该用户已选择角色");
            WebSocketMessageSender.send(session, new SelectRoleJsonWebSocketMessage("角色选择失败，该用户已选择角色"));
        } else {
            //判断是否超过限制
            if (roleLimits.get(roomId).get(role) <= count) {
                System.out.println("角色选择失败，该角色已达到上限");
                WebSocketMessageSender.send(session, new SelectRoleJsonWebSocketMessage("角色选择失败，该角色已达到上限"));
            } else {
                roomRoles.get(roomId).put(playerId, role);
                System.out.println("角色选择成功");
                System.out.println("当前房间角色选择情况" + stringStringMap);
                WebSocketMessageSender.send(session, new SelectRoleJsonWebSocketMessage("角色选择成功"));
            }
        }


    }

    //取消选择角色
    public static void cancelRole(String roomId, String playerId) {
        Map<String, String> stringStringMap = roomRoles.get(roomId);

        if (roomRoles.get(roomId) != null && roomRoles.get(roomId).get(playerId) != null) {
            roomRoles.get(roomId).remove(playerId);
        }
//        System.out.println("当前房间角色选择情况" + stringStringMap);

    }

    //开始游戏后将用户和其所选的角色关系存储到数据库
    public static List<RoleBindingReq> savePlayerRole(String roomId) {
        //获取对应房间已选玩家id和角色类型
        Map<String, String> playerRole = roomRoles.get(roomId);
        //获取映射
        Map<String, String> mapping = roleIdMapping.get(roomId);

        List<RoleBindingReq> roleBindingReq = new ArrayList<>();
        // 将玩家id和角色id绑定
        for (Map.Entry<String, String> entry : playerRole.entrySet()) {
            //获取玩家id
            String playerId1 = entry.getKey();
            //获取角色类型
            String roleType = entry.getValue();
            //获取角色id
            String roleId = mapping.get(roleType);

            RoleBindingReq entity = new RoleBindingReq();
            entity.setUserId(playerId1);
            entity.setRoleId(roleId);

            entity.setRoleType(Integer.parseInt(roleType));
            entity.setRoomId(roomId);
            roleBindingReq.add(entity);
        }
//        System.out.println("角色绑定信息:" + roleBindingReq);


        return roleBindingReq;
    }

    //判断当前房间角色选择是否已满
    public static boolean isFull(String roomId) {
        Map<String, Integer> LimitsMap = roleLimits.get(roomId);
        //统计所有角色总共人数
        long count = LimitsMap.values().stream().mapToInt(Integer::intValue).sum();
        //获取当前房间已选角色人数
        long currentCount = roomRoles.get(roomId).size();
        if (count == currentCount) {
            return true;
        }
        return false;
    }

    //添加用户昵称
    public static void addPlayerName(String roomId, String playerId, String playerName) {
        if (roomNicknames.get(roomId) != null) {
            roomNicknames.get(roomId).put(playerId, playerName);
        }
    }

    //移除用户昵称
    public static void removePlayerName(String roomId, String playerId) {
        if (roomNicknames.get(roomId) != null && roomNicknames.get(roomId).get(playerId) != null) {
            roomNicknames.get(roomId).remove(playerId);
        }
    }

    //获取已选择角色的用户id的key
    public static Set<String> getSelectedPlayerId(String roomId) {
        if (roomRoles.get(roomId) != null) {
            Set<String> ids = roomRoles.get(roomId).keySet();
            return ids;
        } else {
            return null;
        }
    }


    //变化主持人的订单量
    public static void changeCustomerOrder(String roomId, WebSocketSession customer, int order) {
        if (customerOrder.containsKey(roomId) && customerOrder.get(roomId) == 0) {
            customerOrder.put(roomId, order);
        } else {
            WebSocketMessageSender.send(customer, new RoundInitFinishJsonWebSocketMessage("不可重复下订单"));
        }
    }

    public static Integer getCustomerOrder(String roomId) {
        return customerOrder.get(roomId);
    }
}
